package ZJX_net

import (
	"TCP-sever/interface"
	"TCP-sever/utils"
	"errors"
	"fmt"
	"io"
	"net"
)

/*
	连接模块
*/

type Connection struct {
	//隶属于哪个server
	server ZJX_interface.IServer

	//	当前连接Socket套接字
	Conn *net.TCPConn

	//	连接ID
	ConnId uint32

	//	连接状态
	IsClosed bool

	//	告知当前连接停止的chan
	ExitChan chan bool

	//	无缓冲管道，用于读写goroutine之间消息通信
	msgChan chan []byte

	//	消息管理模块
	Mh ZJX_interface.IMsgHandler
}

func NewConnection(server ZJX_interface.IServer, conn *net.TCPConn, connId uint32, msgHandler ZJX_interface.IMsgHandler) *Connection {
	c := &Connection{
		server:   server,
		Conn:     conn,
		ConnId:   connId,
		IsClosed: false,
		msgChan:  make(chan []byte),
		ExitChan: make(chan bool, 1),
		Mh:       msgHandler,
	}
	//将连接放入管理器中
	server.GetConnManager().Add(c)
	return c
}

func (c *Connection) StartRead() {
	fmt.Println("StartRead()... ConnId", c.ConnId)
	defer fmt.Println("ConnId", c.ConnId, "remote Addr is", c.GetRemoteAddr(), "Stop")
	defer c.Stop()
	dp := DataPack{}

	for {
		//先读出头的信息
		buf := make([]byte, dp.GetHeadLen())
		if _, err := io.ReadFull(c.Conn, buf); err != nil {
			fmt.Println("Load head Error:", err)
			break
		}

		//把头信息拿去拆包
		msg, err := dp.UnPack(buf)
		if err != nil {
			fmt.Println("read head Error:", err)
			break
		}

		//使用头信息拿取消息主体
		var data []byte
		if msg.GetDataLen() > 0 {
			data = make([]byte, msg.GetDataLen())
			if _, err := io.ReadFull(c.Conn, data); err != nil {
				fmt.Println("read msg data error:", err)
				break
			}
		}

		msg.SetData(data)
		req := &Request{
			conn: c,
			msg:  msg,
		}

		//如果连接池的大小大于0则代表开启了连接池
		if utils.GlobalObject.WorkerPoolSize > 0 {
			c.Mh.SendMsgTaskQueue(req)
		} else {
			c.Mh.DoMsgHandler(req)
		}
	}
}

/*
	专门给客户端发送消息
*/
func (c *Connection) StartWrite() {
	fmt.Println("[Writer Gortine is ranning]")
	defer fmt.Println(c.GetRemoteAddr().String(), "[conn Writer exit]")
	for {
		select {
		case data := <-c.msgChan:
			if _, err := c.Conn.Write(data); err != nil {
				fmt.Println("Send data error:", err, "Conn Writer exit")
				return
			}
		case <-c.ExitChan:
			//Reader退出时发送消息到该管道，Write也退出
			return
		}
	}
}

//	启动链接 让链接准备开始工作
func (c *Connection) Start() {
	fmt.Println("Conn Start()... ConnID", c.ConnId)
	//启动从当前连接读数据
	go c.StartRead()
	//写数据
	go c.StartWrite()
}

//	停止链接
func (c *Connection) Stop() {
	fmt.Println("Conn Stop()...ConnId", c.ConnId)
	if c.IsClosed {
		return
	}
	c.IsClosed = true

	c.server.GetConnManager().Delete(c)

	//通知写协程退出
	c.ExitChan <- true

	close(c.ExitChan)
	close(c.msgChan)
	c.Conn.Close()
}

//	获取连接绑定的soct conn
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

//	获取连接模块ID
func (c *Connection) GetConnID() uint32 {
	return c.ConnId
}

//	获取远程客户端Tcp状态 IP port
func (c *Connection) GetRemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

//	发送数据 将数据以TVL格式发送给远程客户端
func (c *Connection) SendMsg(id uint32, data []byte) error {
	if c.IsClosed {
		return errors.New("conn is close")
	}

	dp := DataPack{}
	msg := NewMessage(id, data)

	//打包数据
	sendData, err := dp.Pack(msg)
	if err != nil {
		fmt.Println()
	}

	//发送到该连接的Writer协程
	c.msgChan <- sendData

	return nil
}

func (c *Connection) GetConnManager() ZJX_interface.IConnManager {
	return c.server.GetConnManager()
}
